package com.redis.sdk.cachecore;

import com.redis.sdk.RedisClusterUtils;
import com.redis.sdk.Spel;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;

import java.lang.reflect.Method;

@Aspect
@Component
@Order(OrderSort.REDIS_CACHE_ORDER)
@ConditionalOnProperty(prefix = "cache", name = "openRedisCache", havingValue = "true")
@Slf4j
public class CacheRedisAspect {

    @Autowired
    private RedisClusterUtils redisClusterUtils;

    @Autowired
    private CacheProperties cacheProperties;

    /**
     * 拦截指定注解
     */
    @Pointcut("@annotation(com.redis.sdk.cachecore.CacheRedis)")
    public void cacheRedis() {
    }

    /**
     * 拦截指定注解
     */
    @Pointcut("@annotation(com.redis.sdk.cachecore.CacheRedisUpdate)")
    public void cacheRedisUpdate() {
    }

    /**
     * 拦截指定注解
     */
    @Pointcut("@annotation(com.redis.sdk.cachecore.CacheRedisDelete)")
    public void cacheRedisDelete() {
    }

    @Around("cacheRedis()")
    public Object cacheRedis(ProceedingJoinPoint pjp) throws Throwable {
        MethodSignature signature = (MethodSignature) pjp.getSignature();
        Method method = signature.getMethod();

        CacheRedis annotation = method.getAnnotation(CacheRedis.class);
        String key = Spel.parseKey(annotation.value(), method, pjp.getArgs());
        key = annotation.prefix() + key;
        log.info("开始从redis缓存尝试获取数据, key: {}", key);
        Object cacheValue = redisClusterUtils.get(key);
        if (null != cacheValue) {
            log.info("从redis缓存获取到数据, key: {}", key);
            return cacheValue;
        }
        log.info("未从redis缓存获取到数据, key: {}", key);

        Object value = pjp.proceed();
        if (null != value) {
            log.info("开始redis缓存, key: {}", key);
            redisClusterUtils.set(key, value, cacheProperties.getRedisCacheExpireTime());
        }
        return value;
    }

    @Around("cacheRedisUpdate()")
    public Object cacheRedisUpdate(ProceedingJoinPoint pjp) throws Throwable {
        MethodSignature signature = (MethodSignature) pjp.getSignature();
        Method method = signature.getMethod();

        CacheRedisUpdate annotation = method.getAnnotation(CacheRedisUpdate.class);
        String key = Spel.parseKey(annotation.value(), method, pjp.getArgs());
        key = annotation.prefix() + key;
        Object value = pjp.proceed();
        if (null != value) {
            log.info("开始更新redis缓存, key: {}", key);
            redisClusterUtils.set(key, value, cacheProperties.getRedisCacheExpireTime());
        }
        return value;
    }

    @Around("cacheRedisDelete()")
    public Object cacheRedisDelete(ProceedingJoinPoint pjp) throws Throwable {
        MethodSignature signature = (MethodSignature) pjp.getSignature();
        Method method = signature.getMethod();

        CacheRedisDelete annotation = method.getAnnotation(CacheRedisDelete.class);
        String key = Spel.parseKey(annotation.value(), method, pjp.getArgs());
        key = annotation.prefix() + key;
        Object value = pjp.proceed();
        log.info("开始移除redis缓存, key: {}", key);
        redisClusterUtils.delete(key);
        return value;
    }
}
